import asyncio
import datetime
import logging
import time

from asyncua import Client, ua, Node

from examples.my_model import HkDeviceChannel, HkBasePoint
import my_mysql
from my_opcua import SubHandler
import threading
from concurrent.futures import ThreadPoolExecutor

_logger = logging.getLogger(__name__)


def sayhello(node, val, channel_id):
    print("%s say node to %s %s -- [%s]" % (threading.current_thread().getName(), node, val, channel_id))
    my_mysql.helper.get_session() \
        .query(HkBasePoint) \
        .filter(HkBasePoint.device_channel_id == channel_id,
                HkBasePoint.point_address == node) \
        .update({'real_value': str(val), 'value_update_time': datetime.datetime.now()})

    print("完成写入数据库")


def callback(request, result):  # 回调函数，用于取回结果
    print("callback result = %s" % result)


class SubHandler:
    """
    Subscription Handler. To receive events from server for a subscription
    This class is just a sample class. Whatever class having these methods can be used
    """

    def __init__(self, channel_id):
        self.channel_id = channel_id
        self.pool = ThreadPoolExecutor(max_workers=5)  # 创建线程池

    def datachange_notification(self, node: Node, val, data):
        """
        called for every datachange notification from server
        """
        _logger.info("datachange_notification %r %s", node, val)
        print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), node.nodeid.Identifier, val)
        # requests = self.pool.makeRequests(sayhello, node.nodeid.Identifier, val, callback)  # 创建任务

        self.pool.submit(sayhello, node.nodeid.Identifier, val, self.channel_id)
        # my_mysql.helper.get_session() \
        #     .query(HkBasePoint) \
        #     .filter(HkBasePoint.device_channel_id == self.channel_id,
        #             HkBasePoint.point_address == node.nodeid.Identifier) \
        #     .update({'real_value': val, 'value_update_time': datetime.datetime})

    def event_notification(self, event: ua.EventNotificationList):
        """
        called for every event notification from server
        """
        pass

    def status_change_notification(self, status: ua.StatusChangeNotification):
        """
        called for every status change notification from server
        """
        _logger.info("status_notification %s", status)


async def main(ip, port=4840, channel_id=None, interval=1000, ns=3, points=[]):
    handler = SubHandler(channel_id)

    while True:
        client = Client(url="opc.tcp://{}:{}".format(ip, port))
        # client = Client(url="opc.tcp://localhost:53530/OPCUA/SimulationServer/")
        try:
            async with client:
                _logger.warning("Connected")
                subscription = await client.create_subscription(interval, handler)
                node_list = []
                for item in points:
                    node = client.get_node("ns={};s={}".format(ns, item.point_address))
                    node_list.append(node)
                await subscription.subscribe_data_change(tuple(node_list))
                while True:
                    await asyncio.sleep(1)
                    await client.check_connection()  # Throws a exception if connection is lost
        except (ConnectionError, ua.UaError):
            _logger.warning("Reconnecting in 2 seconds")
            await asyncio.sleep(2)


def worker(channel_id, points):
    print("**********************[{}]*****************************".format(channel_id))

    channel = my_mysql.helper.get_session().query(HkDeviceChannel).filter(HkDeviceChannel.id == channel_id).first()

    asyncio.run(main(ip=channel.device_address,
                     channel_id=channel.id,
                     port=channel.device_port,
                     interval=channel.refresh_interval,
                     ns=channel.namespace,
                     points=points))
